/*
方案1
自定义err()和val()传值，apply调用

已修改
问题是无法回到外层了，因为self引用被then修改了
修复方案：把onFulfilled和onRejected改为实例属性
then中的newPromise和oldPromise完全不粘连，避免self赋值
then和catch改为原型方法
---
会影响到
1.then链式调用（结果后抛）
2.所有对self赋值的地方
3.结果外抛


已修改
中断执行流不对，应该忽略后触发的handler
setTimeout中resolve/reject报错，中断执行流有问题
实例携带_resolve/_reject引用不好，应该放到原型上
特殊用例的问题
第一个和中断执行流有关
第二个和手动通知后续promise有关（类似于结果外抛，但条件不好确定--如果resolve/reject是被异步调用的）
第二个问题的解决方案：
改为then等待状态变更，then的作用变为（1.添加handler，2.监听状态变更，并在变更时调用handler）

待修改
性能优化，then监听状态变更，有没有更好的方式


待求证
all/race的内部是中断执行流还是？

*/

;(function(win, debug) {
    win.MyPromise = MyPromise;

    var PING = 'pending';
    var RSED = 'resolved';
    var RJED = 'rejected';
    var FINISH = 'MY_PROMISE_FINISH';   // 中断信号
    var UNDEF;  // const 值为undefined

    function MyPromise(func) {
        if (typeof func !== 'function') {
            err(new Error('new MyPromise: arg is not a function'));
        }

        var self = this;

        //------实例属性
        //---内部属性
        self._PromiseStatus = self._PromiseStatus || PING;
        self._PromiseValue = UNDEF;
        // self._onFulfilled = UNDEF;
        // self._onRejected = UNDEF;
        // self._next = UNDEF; // p和then产生的p之间的联系

        // 立即执行构造器传入的函数
        try {
            func(self._resolve.bind(self), self._reject.bind(self));
        } catch(error) {
            err(error);
        }
    }


    //---原型私有属性
    // _resolve
    MyPromise.prototype._resolve = function(future) {
        var self = this;

        // 已经执行过reject了，忽略resolve
        if (self._PromiseStatus === RJED) {
            return;
        }

        // 更新状态
        self._PromiseValue = future;
        self._PromiseStatus = RSED;

        // 任务队列里已经有了，跳出
        // 避免重复执行handler
        if (self._isListening) {
            return;
        }

        if (typeof self._onFulfilled === 'function') {
            // 展开promise
            if (future instanceof MyPromise) {
                // 把内层结果传递给外层
                // future是内层promise链的最后一个元素
                // future.then拿到内层结果
                // 调用外层resolve传递给外层promise链
                future.then(function(futureValue) {
                    self._resolve(futureValue);
                }, function(error) {
                    if (future._PromiseStatus === RJED) {
                        self._reject(error);
                    }
                    else {
                        self._resolve(error);
                    }
                });
            }
            else {
                // 执行handler
                // 并将handler的返回值传递给下一个promise
                // P.S._next不用做检查，因为如果有handler，就肯定调用过then了
                self._next._PromiseValue = self._onFulfilled.call(null, future);
                // 更新下一个promise的状态
                self._next._PromiseStatus = RSED;
            }
        }

        // 中断func的执行流，防止后面代码执行
        // throw new Error(FINISH);
    };
    
    MyPromise.prototype._reject = function(error) {
        var self = this;

        // 已经执行过resolve了，忽略reject
        if (self._PromiseStatus === RSED) {
            return;
        }

        // 更新状态
        self._PromiseValue = error;
        self._PromiseStatus = RJED;

        // 任务队列里已经有了，跳出
        // 避免重复执行handler
        if (self._isListening) {
            return;
        }

        if (typeof self._onRejected === 'function') {
            // 执行handler
            // 并将handler的返回值传递给下一个promise
            self._next._PromiseValue = self._onRejected.call(null, error);
            // 更新下一个promise的状态
            // onRejected之后，状态为resolved
            self._next._PromiseStatus = RSED;
        }
        else {
            // 异步检查报错（等待同步的then | catch）
            nextTick(function() {
                if (typeof self._onRejected === 'function') {
                    // then已经处理过了，不报错
                    return;
                }

                // 报错
                if (!(error instanceof Error)) {
                    error = new Error('reject in MyPromise: ' + error);
                }
                err(error);
            });
        }

        // 中断func的执行流，防止后面代码执行
        // throw new Error(FINISH);
    };

    //---原型公开属性
    // then 添加handler
    MyPromise.prototype.then = function(onFulfilled, onRejected) {
        // 处理错误参数
        if (arguments.length === 1 && typeof onFulfilled !== 'function') {
            // 单参且参数错误，忽略掉
            return this;
        }

        var self = this;
        var isCatch = false;

        var newPromise = new MyPromise(emptyF);
        // 建立联系
        self._next = newPromise;
        
        // 同步添加handler
        if (typeof onFulfilled === 'function') {
debug('add onFulfilled handler');
            self._onFulfilled = onFulfilled;
        }
        if (typeof onRejected === 'function') {
debug('add onRejected handler');
            self._onRejected = onRejected;

            // 判断catch（只添加否定handler时要保证状态传递）
            if (typeof onFulfilled !== 'function') {
                // onFulfilled如果不是函数，就会被忽略掉
                // 此时相当于调用catch
                isCatch = true;
            }
        }

        // 异步监听状态变更，并在变更发生后执行handler
        function listen() {
            nextTick(function() {
                if (self._PromiseStatus === RSED) {
                    // 更新监听状态
                    self._isListening = false;
debug('onFulfilled now');
                    // 复制状态和值 self -> newPromise
                    if (isCatch) {
                        extend(newPromise, self);
                    }
                    // 由oldPromise执行handler，并将handler返回值通过_next传递给newPromise
                    self._resolve(self._PromiseValue);
                }
                else if (self._PromiseStatus === RJED) {
                    // 更新监听状态
                    self._isListening = false;
debug('onRejected now');
                    // 处理错误参数
                    if (typeof onRejected === 'function') {
                        // 执行handler
                        self._reject(self._PromiseValue);
                    }
                }
                else {
                    // 状态没变（pending），继续监听
                    listen();
                }
            });
            
        }

        listen();
        self._isListening = true;
        
        // 支持链式调用，结果自动后抛
        // setTimeout(function() {
        //     console.log(newPromise);
        // }, 1000);
        return newPromise;
    };

    // catch 添加否定handler
    MyPromise.prototype['catch'] = function(onRejected) {
        return this.then(UNDEF, onRejected);
    };


    //------静态属性
    //resolve 返回promise对象
    MyPromise.resolve = function(value) {
        var p;

        // promise不变
        if (value instanceof MyPromise) {
            p = value;
        }
        // 包装!promise
        else {
            p = new MyPromise(emptyF);

            // thenable
            if (typeof value === 'object' && typeof value.then === 'function') {
                // 把obj.then包起来
                var _then = p.then;
                p.then = function(onFulfilled, onRejected) {
                    var resolved = false;

                    value.then(function(future) {
                        if (!resolved) {
                            nextTick(function() {
                                // 更新状态
                                p._PromiseStatus = RSED;
                                p._PromiseValue = onFulfilled(future);
                            });
                            // 禁止触发onRejected
                            resolved = true;
                        }
                    }, function(error) {
                        if (!resolved) {
                            nextTick(function() {
                                // 更新状态
                                p._PromiseStatus = RSED;
                                p._PromiseValue = onRejected(error);
                            });
                            // 禁止触发onFulfilled
                            resolved = true;
                        }
                    });

                    // 恢复原then
                    p.then = _then;

                    return p;
                };
            }
            // !thenable
            else {
                p._PromiseValue = value;
                p._PromiseStatus = RSED;
            }
        }

        return p;
    };
    //reject 返回promise对象
    MyPromise.reject = function(reason) {
        var p = new MyPromise(emptyF);

        p._PromiseValue = reason;
        p._PromiseStatus = RJED;

        return p;
    };
    // all 并发，要么全都正常完成，要么因错误中断，未完成的都停下来
    MyPromise.all = function(arr) {
        var p = new MyPromise(function(resolve, reject) {
            var breakout = false;
            var futures = [];

            function onFulfilled(future) {
                futures.push(future);
                // 全肯定
                if (futures.length === arr.length) {
                    p._PromiseStatus = RSED;
                    p._PromiseValue = futures;
                }
            }
            function onRejected(error) {
                if (!breakout) {
                    breakout = true;
                    p._PromiseStatus = RJED;
                    p._PromiseValue = error;
                }
            }

            for (var i = 0; i < arr.length; i++) {
                if (arr[i] instanceof MyPromise) {
                    arr[i].then(onFulfilled, onRejected);
                }
                else {
                    // !promise直接放进futures结果集，异步
                    ;(function(future) {
                        nextTick(function() {
                            onFulfilled(future);
                        });
                    })(arr[i]);
                }
            }

            // console.log(i);
            // console.log(futures);
        });
        
        return p;
    };
    // race 赛跑，返回最早出现的结果
    MyPromise.race = function(arr) {
        var p = new MyPromise(function(resolve, reject) {
            var breakout = false;

            function onFulfilled(future) {
                if (!breakout) {
                    breakout = true;
                    p._PromiseStatus = RSED;
                    p._PromiseValue = future;
                }
            }
            function onRejected(error) {
                if (!breakout) {
                    breakout = true;
                    p._PromiseStatus = RJED;
                    p._PromiseValue = error;
                }
            }

            for (var i = 0; i < arr.length; i++) {
                if (arr[i] instanceof MyPromise) {
                    arr[i].then(onFulfilled, onRejected);
                }
                else {
                    // !promise直接resolved，异步
                    if (!breakout) {
                        ;(function(future) {
                            nextTick(function() {
                                onFulfilled(future);
                            });
                        })(arr[i]);
                    }
                }
            }
        });

        return p;
    };


    //------工具方法
    function emptyF() {}
    function extend(newPromise, oldPromise) {
        newPromise._PromiseStatus = oldPromise._PromiseStatus;
        newPromise._PromiseValue = oldPromise._PromiseValue;
    }
    function err(error) {
        if (error instanceof Error && error.message === FINISH) {
            // do nothing
        }
        else {
            throw error;
        }
    }
    function nextTick(fn) {
        setTimeout(function() {
            try {
                fn();
            }
            catch (error) {
                err(error);
            }
        }, 1);
    }
})(window, function(arg) {
    // console.log(arg);
});